package com.googlecode.totallylazy.lambda.weaving;

import com.googlecode.totallylazy.Callables;
import com.googlecode.totallylazy.Function1;
import com.googlecode.totallylazy.Maps;
import com.googlecode.totallylazy.Pair;
import com.googlecode.totallylazy.Sequence;

import java.io.ByteArrayInputStream;

import static com.googlecode.totallylazy.Sequences.one;

public class Weaver {
    private final ClassLoader classLoader;

    public Weaver(ClassLoader classLoader) {
        this.classLoader = classLoader;
    }

    public Weaver() {
        this(ClassLoader.getSystemClassLoader());
    }

    public Iterable<Pair<String, byte[]>> classes(String name, byte[] bytes) {
        try {
            if (name.endsWith(".class")) {
                return weave(name, bytes);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return one(Pair.pair(name, bytes));
    }

    private Iterable<Pair<String, byte[]>> weave(String name, byte[] input) throws Exception {
        final LambdaTreeTransformer lambdaTreeTransformer = new LambdaTreeTransformer();
        byte[] output = lambdaTreeTransformer.transform(classLoader, new ClassFilter("", "", ""), null, input);
        if(output == null) return one(Pair.pair(name, input));
        Sequence<Pair<String, byte[]>> newClasses = Maps.pairs(lambdaTreeTransformer.getLambdasByClassName()).map(Callables.<String, byte[], String>first(filename()));
        return newClasses.cons(Pair.pair(name, output));
    }

    private Function1<String, String> filename() {
        return new Function1<String, String>() {
            @Override
            public String call(String name) throws Exception {
                return name.replace('.', '/').concat(".class");
            }
        };
    }
}
